package com.tbit.uqbike.service.business.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tbit.common.constant.OperationPlatform;
import com.tbit.common.entity.UserOpLog;
import com.tbit.common.entity.view.Result;
import com.tbit.common.utils.TbitHttpServiceUtil;
import com.tbit.uqbike.constant.BrandRemoteConfigConstant;
import com.tbit.uqbike.enums.SystemCodeEnum;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.*;
import com.tbit.uqbike.object.pojo.dto.CouponBatchGiftDTO;
import com.tbit.uqbike.object.pojo.dto.PackageDelayDTO;
import com.tbit.uqbike.object.pojo.vo.AccountPathVO;
import com.tbit.uqbike.object.pojo.vo.GiveRideCardVo;
import com.tbit.uqbike.object.value.LoginInfo;
import com.tbit.uqbike.service.business.CouponService;
import com.tbit.uqbike.service.business.UserService;
import com.tbit.uqbike.service.rpcservice.PurviewService;
import com.tbit.uqbike.webmanager.business.user_op_log.service.UserOpLogService;
import com.tbit.uqbike.webmanager.dao.capital.RefundLogDao;
import com.tbit.uqbike.webmanager.dao.core.*;
import com.tbit.uqbike.webmanager.dao.log.CouponGiftLogDao;
import com.tbit.uqbike.webmanager.sms.ApiStoreMsgUtils;
import com.tbit.uqbike.webmanager.sms.ClzySmsAuthUtil;
import com.tbit.uqbike.webmanager.util.Assert;
import com.tbit.utils.DateTimeUtil;
import com.tbit.utils.NullUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author chenmengran
 * @Description: 优惠券
 * @date 2019\12\27 002716:43
 */
@Service
@Slf4j
public class CouponServiceImpl implements CouponService {
    @Autowired
    private CouponDao couponDao;
    @Autowired
    private CouponGiftLogDao couponGiftLogDao;
    @Autowired
    private PurviewService purviewService;
    @Autowired
    private CouponUserDao couponUserDao;
    @Autowired
    private RefundLogDao refundLogDao;
    @Autowired
    private AccountDao accountDao;
    @Autowired
    private UserService userService;
    @Resource
    private SmsAuthConfigDao smsAuthConfigDao;
    @Autowired
    private UsermsgDao usermsgDao;
    @Resource
    private SmsAuthConfigServiceImpl smsAuthConfigService;
    @Autowired
    private UserOpLogService userOpLogService;

    @Override
    public void add(LoginInfo loginInfo, Coupon coupon) {
        if (!purviewService.purviewCheck(loginInfo.id, coupon.getAccountId())) {
            throw new BaseException(SystemCodeEnum.NO_PRIVILEGE);
        }
        if (coupon.getCouponId() != null) {
            Coupon c = couponDao.getByCouponId(coupon.getCouponId());
            if (c != null) {
                couponDao.update(coupon);
            }
        } else {
            Assert.notNull(coupon.getCouponMoney(), "ver.couponMoney .notNull");
            Assert.notNull(coupon.getCouponTime(), "ver.couponTime .notNull");
            Assert.notNull(coupon.getCouponType(), "ver.couponType .notNull");
            Assert.notNull(coupon.getName(), "ver.name.notNull");
            Assert.notNull(coupon.getIsValid(), "ver.isValid .notNull");

            couponDao.insertUP(coupon);
        }
    }

    @Override
    public List<Coupon> queryPage(LoginInfo loginInfo, Integer accountId, Integer pageNO, Integer rowCount) {
        if (!purviewService.purviewCheck(loginInfo.id, accountId)) {
            throw new BaseException(SystemCodeEnum.NO_PRIVILEGE);
        }
        Map<String, Object> params = new HashMap<>();
        params.put("accountId", accountId);
        params.put("rowCount", rowCount);
        params.put("start", (pageNO - 1) * rowCount);

        return couponDao.queryPage(params);
    }

    @Override
    public Integer queryCount(Integer accountId) {
        return couponDao.getTotal(accountId);
    }

    @Override
    public Coupon getBycouponId(Integer couponId) {
        return couponDao.getByCouponId(couponId);
    }

    @Override
    public List<Coupon> getCouponIsVail(Integer accountId) {
        Map<String, Object> params = new HashMap<>();
        params.put("accountId", accountId);
        params.put("isValid", 1);
        params.put("time", new Date());

        return couponDao.getCouponIsVail(params);
    }

    @Override
    public void update(Coupon coupon) {
        couponDao.update(coupon);
    }

    @Override
    public List<CouponUser> getByUserIdPage(Integer userId, Integer accountId, Integer pageNO, Integer pageSize) {
        Map<String, Object> params = new HashMap<>();
        params.put("userId", userId);
        params.put("accountId", accountId);
        params.put("rowCount", pageSize);
        params.put("page", (pageNO - 1) * pageSize);
        return couponDao.getByUserIdPage(params);
    }

    @Override
    public Integer getByUserIdCount(Integer userId, Integer accountId) {
        Map<String, Object> params = new HashMap<>();
        params.put("userId", userId);
        params.put("accountId", accountId);
        return couponDao.getByUserIdCount(params);
    }

    @Override
    public void addBatch(CouponUser couponUser, Integer num, Long endTime, Boolean sendMessage, LoginInfo loginInfo) {
        if (num > 1000 || num <= 0) {
            throw new BaseException("优惠劵赠送数量有误,请输入1-1000之间的整数");
        }
        if (endTime != null && endTime < System.currentTimeMillis()) {
            throw new BaseException("优惠劵失效时间不能小于今天");
        }
        Coupon couponInDb = getBycouponId(couponUser.getCouponId());
        if (couponInDb == null) {
            throw new BaseException(SystemCodeEnum.COUPON_NOT_EXIST);
        }
        User user = userService.getByUserId(couponUser.getUserId());
        if (Objects.isNull(user)) {
            throw new BaseException(SystemCodeEnum.USER_NOT_EXIST);
        }
        Account franchisee = accountDao.getAgentId(couponInDb.getAccountId());
        Integer brandId = franchisee.getParentId();
        if (!brandId.equals(user.getAccountId())) {
            throw new BaseException(SystemCodeEnum.SYSTEM_ERROR, "当前优惠劵所在品牌下不存在此用户");
        }
        List<CouponUser> list = new LinkedList<>();
        for (int i = 0; i < num; i++) {
            final CouponUser couponUserNew = new CouponUser();
            couponUserNew.setAccountId(couponInDb.getAccountId());
            couponUserNew.setIsUse(0);
            couponUserNew.setCouponId(couponUser.getCouponId());
            couponUserNew.setIsValid(1);
            couponUserNew.setUserId(user.getUserId());
            couponUserNew.setRecTime(DateTimeUtil.getNowTime());
            couponUserNew.setExpireTime(DateTimeUtil.DateTimeToString(couponInDb.getEndTime()));
            if (endTime != null) {
                couponUserNew.setExpireTime(DateTimeUtil.getDateTimeByGL(endTime));
            }
            list.add(couponUserNew);
        }
        couponDao.addBatch(list);
        if (Boolean.TRUE.equals(sendMessage)) {
            //获取短信配置
            Account brandArea = accountDao.getByAccountId(brandId);
            SmsAuthConfig smsAuthConfig = smsAuthConfigDao.selectSmsConfigAndType(brandId, 14);

            //优驱api配置
            BrandRemoteConfig brandRemoteConfigDB = smsAuthConfigService.getBrandRemoteConfig(brandId,
                    BrandRemoteConfigConstant.TBIT_CONFIG);
            // [xx出行]尊敬的用户，您有新的优惠券到账，请登录xx出行小程序"我的-我的优惠券"查看。
            if (!NullUtils.isEmpty(smsAuthConfig)) {
                //寻程发送短信*/
                ApiStoreMsgUtils.sendModelSms(user.getPhone(), smsAuthConfig.getSmsCodeKey(), Integer.valueOf(smsAuthConfig.getModelId()), brandArea.getName(),
                        "尊敬的用户，您有新的优惠券到账，请登录" + brandArea.getName() + "小程序'我的-我的优惠券'查看"
                );
            }else if (Objects.nonNull(brandRemoteConfigDB)){
                String templateId = smsAuthConfigService.getBrandRemoteConfigValue(brandId, BrandRemoteConfigConstant.SMS_COUPON_ARRIVAL);
                if (StringUtils.isNotBlank(templateId)){
                    //优驱api发送短信
                    String key = brandRemoteConfigDB.getParamKV();
                    String[] strings = key.split("&");
                    Map<String,Object> map = new HashMap<>();
                    map.put("brandName", brandArea.getName());
                    boolean result = TbitHttpServiceUtil.sendSms(strings[0].substring(strings[0].indexOf("=") + 1),
                            strings[1].substring(strings[1].indexOf("=") + 1)
                            , strings[2].substring(strings[2].indexOf("=") + 1), user.getPhone(), JSON.toJSONString(map), Integer.valueOf(templateId));
                    if (!result) {
                        log.info("手机号：{}优惠券到账提醒优驱api短信发送失败", user.getPhone());
                    }
                }else {
                    log.info("优惠券赠送短信发送失败，未配置短信模板id");
                }
            }else {
                Map<String, Integer> noteMap = new HashMap<>(4);
                noteMap.put("accountId", brandId);
                noteMap.put("configType", 4);
                BrandRemoteConfig brandRemoteConfig = smsAuthConfigDao.getByConfigType(noteMap);
                if (brandRemoteConfig != null) {
                    String[] strings = brandRemoteConfig.getParamKV().split("&");
                    String accounts = strings[0].substring(strings[0].indexOf("=") + 1);
                    String password = strings[1].substring(strings[1].indexOf("=") + 1);
                    ClzySmsAuthUtil.sendSms(accounts, password, "尊敬的用户，您有新的优惠券到账，请登录" + brandArea.getName() + "小程序'我的-我的优惠券'查看", user.getPhone());
                }
            }
            usermsgDao.insertSelective(new Usermsg(user.getUserId(), "您的优惠劵已到账", String.format("送您%s张[%s]优惠劵,有效期至%s", num, couponInDb.getName(),
                    DateTimeUtil.getDateTimeByGL(endTime))));
        }
        AccountPathVO account = accountDao.getAccountPathByRegionId(couponInDb.getAccountId(), 3);
        List<CouponGiftLog> giftLogList = list.stream().map(x -> new CouponGiftLog()
                .setCouponUserId(x.getCouponuserId())
                .setCouponId(x.getCouponId())
                .setCouponName(couponInDb.getName())
                .setBrandId(account.getBrandId())
                .setFranchiseeId(account.getFranchiseeId())
                .setRegionId(account.getRegionId())
                .setAccountPath(account.montageAccountPath())
                .setUserId(x.getUserId())
                .setUserPhone(user.getPhone())
                .setUserName(user.getName())
                .setAccountUserName(loginInfo.getName())
                .setAccountUserId(loginInfo.getId())
                .setGiftTime(x.getRecTime())).collect(Collectors.toList());
        CompletableFuture.allOf(CompletableFuture.runAsync(() -> addGiftLog(giftLogList)));

        // 插入用户操作日志
        userOpLogService.insertSingle(UserOpLog.builder()
                .accountId(couponUser.getAccountId())
                .opUser(loginInfo.getName())
                .opUserPhone(loginInfo.getPhone())
                .targetUser(user.getName())
                .targetUserPhone(user.getPhone())
                .operation("优惠券变动")
                .opType("发放")
                .opPlatform(OperationPlatform.MANAGER.code)
                .opTime(LocalDateTime.now())
                .detail("优惠券ID: " + couponUser.getCouponId() + "\n优惠券数量: " + num)
                .result(true)
                .build());
    }


    @Override
    public void userCouponEdit(Integer couponUserId, Integer userId) {
        couponDao.userCouponEdit(couponUserId, userId);
    }

    @Override
    public void modifyCouponExpireTime(PackageDelayDTO delayDTO) {
        CouponUser couponUser = couponUserDao.findByCouponUserIdAndUserId(Integer.parseInt(delayDTO.getBusId()), delayDTO.getUserId());
        if (couponUser == null) {
            throw new BaseException(SystemCodeEnum.COUPON_NOT_EXIST);
        }
        if (couponUser.getIsUse() == 1) {
            throw new BaseException("优惠劵已使用,不能延期");
        }
        if (StringUtils.isNotBlank(couponUser.getOrderNO())) {
            List<RefundLog> refundLogs = refundLogDao.selectList(new LambdaQueryWrapper<RefundLog>().eq(RefundLog::getMerchantNO, couponUser.getOrderNO()));
            if (CollectionUtils.isNotEmpty(refundLogs)) {
                throw new BaseException("优惠劵已产生退款,不能延期");
            }
        }
        couponUser.setExpireTime(DateUtil.formatDate(new Date(delayDTO.getDelayTime())));
        if (couponUser.getIsValid() == 0) {
            couponUser.setIsValid(1);
        }
        couponUserDao.update(couponUser);
    }

    @Override
    public List<CouponGiftLog> listCouponGiftLog(CouponGiftLog couponGiftLog, Date startTime, Date endTime) {
        LambdaQueryWrapper<CouponGiftLog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CouponGiftLog::getRegionId, couponGiftLog.getRegionId());
        if (StringUtils.isNotBlank(couponGiftLog.getUserPhone())) {
            queryWrapper.eq(CouponGiftLog::getUserPhone, couponGiftLog.getUserPhone());
        }
        if (Objects.nonNull(startTime) && Objects.nonNull(endTime)){
            queryWrapper.between(CouponGiftLog::getGiftTime, startTime, endTime);
        }
        queryWrapper.orderBy(true, false, CouponGiftLog::getId);
        return couponGiftLogDao.selectList(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public Result<List<GiveRideCardVo>> addBatchCoupons(CouponBatchGiftDTO couponGiftDTO) {
        couponGiftDTO.valid();
        Set<String> userPhones = couponGiftDTO.getUserPhones();
        Integer sendCount = couponGiftDTO.getNum();
        Integer couponId = couponGiftDTO.getCouponId();
        Integer accountId = couponGiftDTO.getAccountId();
        Long expireTime = couponGiftDTO.getExpireTime();
        Coupon coupon = getBycouponId(couponId);
        if (coupon == null) {
            throw new BaseException(SystemCodeEnum.COUPON_NOT_EXIST);
        }
        if (!Objects.equals(coupon.getAccountId(), accountId)) {
            throw new BaseException("赠送的优惠券不属于该运营区域,请重新配置优惠劵后再发放");
        }
        AccountPathVO account = accountDao.getAccountPathByRegionId(accountId, 3);
        final Map<String, User> userMap = userService.mapByUserPhone(userPhones, account.getBrandId());
        List<CouponGiftLog> giftLogList = new ArrayList<>();
        List<CouponUser> dataList = new LinkedList<>();
        List<Usermsg> userMessageList = new ArrayList<>();
        List<GiveRideCardVo> failList = new ArrayList<>();
        for (String userPhone : userPhones) {
            GiveRideCardVo giveRideCardVo = null;
            final User user = userMap.get(userPhone);
            if (Objects.isNull(user)) {
                giveRideCardVo = new GiveRideCardVo();
                giveRideCardVo.setPhone(userPhone);
                giveRideCardVo.setFailMsg("用户不存在");
                failList.add(giveRideCardVo);
                continue;
            }
            for (int i = 0; i < sendCount; i++) {
                final CouponUser couponUser = new CouponUser();
                couponUser.setAccountId(accountId);
                couponUser.setIsUse(0);
                couponUser.setIsValid(1);
                couponUser.setCouponId(couponId);
                couponUser.setUserId(user.getUserId());
                couponUser.setRecTime(DateTimeUtil.getNowTime());
                couponUser.setPhone(user.getPhone());
                couponUser.setExpireTime(Optional.ofNullable(expireTime).map(DateTimeUtil::getDateTimeByGL)
                        .orElse(DateTimeUtil.DateTimeToString(coupon.getEndTime())));
                dataList.add(couponUser);
            }
            if (dataList.size() >= 500) {
                couponDao.addBatch(dataList);
                giftLogList.addAll(dataList.stream().map(x -> {
                    User userNew = userMap.get(x.getPhone());
                    return new CouponGiftLog()
                            .setCouponUserId(x.getCouponuserId())
                            .setCouponId(x.getCouponId())
                            .setCouponName(coupon.getName())
                            .setBrandId(account.getBrandId())
                            .setFranchiseeId(account.getFranchiseeId())
                            .setRegionId(account.getRegionId())
                            .setAccountPath(account.montageAccountPath())
                            .setUserId(x.getUserId())
                            .setUserPhone(x.getPhone())
                            .setUserName(Optional.ofNullable(userNew).map(User::getName).orElse("-"))
                            .setAccountUserName(couponGiftDTO.getLoginInfo().getName())
                            .setAccountUserId(couponGiftDTO.getLoginInfo().getId())
                            .setGiftTime(x.getRecTime());
                })
                        .collect(Collectors.toList()));
                dataList = new LinkedList<>();
            }
            //添加消息
            userMessageList.add(new Usermsg(user.getUserId(), "您的优惠劵已到账", String.format("送您%s张[%s]优惠劵,有效期至%s", sendCount, coupon.getName(),
                    DateTimeUtil.getDateTimeByGL(expireTime))));
        }
        if (CollectionUtils.isNotEmpty(dataList)) {
            couponDao.addBatch(dataList);
            giftLogList.addAll(dataList.stream().map(x -> {
                User user = userMap.get(x.getPhone());
                return new CouponGiftLog()
                        .setCouponUserId(x.getCouponuserId())
                        .setCouponId(x.getCouponId())
                        .setCouponName(coupon.getName())
                        .setBrandId(account.getBrandId())
                        .setFranchiseeId(account.getFranchiseeId())
                        .setRegionId(account.getRegionId())
                        .setAccountPath(account.montageAccountPath())
                        .setUserId(x.getUserId())
                        .setUserPhone(x.getPhone())
                        .setUserName(Optional.ofNullable(user).map(User::getName).orElse("-"))
                        .setAccountUserName(couponGiftDTO.getLoginInfo().getName())
                        .setAccountUserId(couponGiftDTO.getLoginInfo().getId())
                        .setGiftTime(x.getRecTime());
            })
                    .collect(Collectors.toList()));
        }
        //通知用户。
        if (CollectionUtils.isNotEmpty(userMessageList)) {
            usermsgDao.insertBatch(userMessageList);
        }
        CompletableFuture.allOf(CompletableFuture.runAsync(() -> addGiftLog(giftLogList)));
        return Result.success(failList);
    }

    @Override
    public CouponUser selectByAccountIdList(Integer userId, List<Integer> accountIdList) {
        return couponDao.selectByAccountIdList(userId, accountIdList);
    }

    private void addGiftLog(List<CouponGiftLog> giftLogList) {
        if (CollectionUtils.isEmpty(giftLogList)) {
            return;
        }
        giftLogList.forEach(x -> couponGiftLogDao.insert(x));
    }

}
